home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / python2.5 / idlelib / Debugger.py < prev    next >
Text File  |  2008-10-05  |  16KB  |  482 lines

  1. import os
  2. import bdb
  3. import types
  4. from Tkinter import *
  5. from WindowList import ListedToplevel
  6. from ScrolledList import ScrolledList
  7. import macosxSupport
  8.  
  9.  
  10. class Idb(bdb.Bdb):
  11.  
  12.     def __init__(self, gui):
  13.         self.gui = gui
  14.         bdb.Bdb.__init__(self)
  15.  
  16.     def user_line(self, frame):
  17.         if self.in_rpc_code(frame):
  18.             self.set_step()
  19.             return
  20.         message = self.__frame2message(frame)
  21.         self.gui.interaction(message, frame)
  22.  
  23.     def user_exception(self, frame, info):
  24.         if self.in_rpc_code(frame):
  25.             self.set_step()
  26.             return
  27.         message = self.__frame2message(frame)
  28.         self.gui.interaction(message, frame, info)
  29.  
  30.     def in_rpc_code(self, frame):
  31.         if frame.f_code.co_filename.count('rpc.py'):
  32.             return True
  33.         else:
  34.             prev_frame = frame.f_back
  35.             if prev_frame.f_code.co_filename.count('Debugger.py'):
  36.                 # (that test will catch both Debugger.py and RemoteDebugger.py)
  37.                 return False
  38.             return self.in_rpc_code(prev_frame)
  39.  
  40.     def __frame2message(self, frame):
  41.         code = frame.f_code
  42.         filename = code.co_filename
  43.         lineno = frame.f_lineno
  44.         basename = os.path.basename(filename)
  45.         message = "%s:%s" % (basename, lineno)
  46.         if code.co_name != "?":
  47.             message = "%s: %s()" % (message, code.co_name)
  48.         return message
  49.  
  50.  
  51. class Debugger:
  52.  
  53.     vstack = vsource = vlocals = vglobals = None
  54.  
  55.     def __init__(self, pyshell, idb=None):
  56.         if idb is None:
  57.             idb = Idb(self)
  58.         self.pyshell = pyshell
  59.         self.idb = idb
  60.         self.frame = None
  61.         self.make_gui()
  62.         self.interacting = 0
  63.  
  64.     def run(self, *args):
  65.         try:
  66.             self.interacting = 1
  67.             return self.idb.run(*args)
  68.         finally:
  69.             self.interacting = 0
  70.  
  71.     def close(self, event=None):
  72.         if self.interacting:
  73.             self.top.bell()
  74.             return
  75.         if self.stackviewer:
  76.             self.stackviewer.close(); self.stackviewer = None
  77.         # Clean up pyshell if user clicked debugger control close widget.
  78.         # (Causes a harmless extra cycle through close_debugger() if user
  79.         # toggled debugger from pyshell Debug menu)
  80.         self.pyshell.close_debugger()
  81.         # Now close the debugger control window....
  82.         self.top.destroy()
  83.  
  84.     def make_gui(self):
  85.         pyshell = self.pyshell
  86.         self.flist = pyshell.flist
  87.         self.root = root = pyshell.root
  88.         self.top = top = ListedToplevel(root)
  89.         self.top.wm_title("Debug Control")
  90.         self.top.wm_iconname("Debug")
  91.         top.wm_protocol("WM_DELETE_WINDOW", self.close)
  92.         self.top.bind("<Escape>", self.close)
  93.         #
  94.         self.bframe = bframe = Frame(top)
  95.         self.bframe.pack(anchor="w")
  96.         self.buttons = bl = []
  97.         #
  98.         self.bcont = b = Button(bframe, text="Go", command=self.cont)
  99.         bl.append(b)
  100.         self.bstep = b = Button(bframe, text="Step", command=self.step)
  101.         bl.append(b)
  102.         self.bnext = b = Button(bframe, text="Over", command=self.next)
  103.         bl.append(b)
  104.         self.bret = b = Button(bframe, text="Out", command=self.ret)
  105.         bl.append(b)
  106.         self.bret = b = Button(bframe, text="Quit", command=self.quit)
  107.         bl.append(b)
  108.         #
  109.         for b in bl:
  110.             b.configure(state="disabled")
  111.             b.pack(side="left")
  112.         #
  113.         self.cframe = cframe = Frame(bframe)
  114.         self.cframe.pack(side="left")
  115.         #
  116.         if not self.vstack:
  117.             self.__class__.vstack = BooleanVar(top)
  118.             self.vstack.set(1)
  119.         self.bstack = Checkbutton(cframe,
  120.             text="Stack", command=self.show_stack, variable=self.vstack)
  121.         self.bstack.grid(row=0, column=0)
  122.         if not self.vsource:
  123.             self.__class__.vsource = BooleanVar(top)
  124.         self.bsource = Checkbutton(cframe,
  125.             text="Source", command=self.show_source, variable=self.vsource)
  126.         self.bsource.grid(row=0, column=1)
  127.         if not self.vlocals:
  128.             self.__class__.vlocals = BooleanVar(top)
  129.             self.vlocals.set(1)
  130.         self.blocals = Checkbutton(cframe,
  131.             text="Locals", command=self.show_locals, variable=self.vlocals)
  132.         self.blocals.grid(row=1, column=0)
  133.         if not self.vglobals:
  134.             self.__class__.vglobals = BooleanVar(top)
  135.         self.bglobals = Checkbutton(cframe,
  136.             text="Globals", command=self.show_globals, variable=self.vglobals)
  137.         self.bglobals.grid(row=1, column=1)
  138.         #
  139.         self.status = Label(top, anchor="w")
  140.         self.status.pack(anchor="w")
  141.         self.error = Label(top, anchor="w")
  142.         self.error.pack(anchor="w", fill="x")
  143.         self.errorbg = self.error.cget("background")
  144.         #
  145.         self.fstack = Frame(top, height=1)
  146.         self.fstack.pack(expand=1, fill="both")
  147.         self.flocals = Frame(top)
  148.         self.flocals.pack(expand=1, fill="both")
  149.         self.fglobals = Frame(top, height=1)
  150.         self.fglobals.pack(expand=1, fill="both")
  151.         #
  152.         if self.vstack.get():
  153.             self.show_stack()
  154.         if self.vlocals.get():
  155.             self.show_locals()
  156.         if self.vglobals.get():
  157.             self.show_globals()
  158.  
  159.     def interaction(self, message, frame, info=None):
  160.         self.frame = frame
  161.         self.status.configure(text=message)
  162.         #
  163.         if info:
  164.             type, value, tb = info
  165.             try:
  166.                 m1 = type.__name__
  167.             except AttributeError:
  168.                 m1 = "%s" % str(type)
  169.             if value is not None:
  170.                 try:
  171.                     m1 = "%s: %s" % (m1, str(value))
  172.                 except:
  173.                     pass
  174.             bg = "yellow"
  175.         else:
  176.             m1 = ""
  177.             tb = None
  178.             bg = self.errorbg
  179.         self.error.configure(text=m1, background=bg)
  180.         #
  181.         sv = self.stackviewer
  182.         if sv:
  183.             stack, i = self.idb.get_stack(self.frame, tb)
  184.             sv.load_stack(stack, i)
  185.         #
  186.         self.show_variables(1)
  187.         #
  188.         if self.vsource.get():
  189.             self.sync_source_line()
  190.         #
  191.         for b in self.buttons:
  192.             b.configure(state="normal")
  193.         #
  194.         self.top.wakeup()
  195.         self.root.mainloop()
  196.         #
  197.         for b in self.buttons:
  198.             b.configure(state="disabled")
  199.         self.status.configure(text="")
  200.         self.error.configure(text="", background=self.errorbg)
  201.         self.frame = None
  202.  
  203.     def sync_source_line(self):
  204.         frame = self.frame
  205.         if not frame:
  206.             return
  207.         filename, lineno = self.__frame2fileline(frame)
  208.         if filename[:1] + filename[-1:] != "<>" and os.path.exists(filename):
  209.             self.flist.gotofileline(filename, lineno)
  210.  
  211.     def __frame2fileline(self, frame):
  212.         code = frame.f_code
  213.         filename = code.co_filename
  214.         lineno = frame.f_lineno
  215.         return filename, lineno
  216.  
  217.     def cont(self):
  218.         self.idb.set_continue()
  219.         self.root.quit()
  220.  
  221.     def step(self):
  222.         self.idb.set_step()
  223.         self.root.quit()
  224.  
  225.     def next(self):
  226.         self.idb.set_next(self.frame)
  227.         self.root.quit()
  228.  
  229.     def ret(self):
  230.         self.idb.set_return(self.frame)
  231.         self.root.quit()
  232.  
  233.     def quit(self):
  234.         self.idb.set_quit()
  235.         self.root.quit()
  236.  
  237.     stackviewer = None
  238.  
  239.     def show_stack(self):
  240.         if not self.stackviewer and self.vstack.get():
  241.             self.stackviewer = sv = StackViewer(self.fstack, self.flist, self)
  242.             if self.frame:
  243.                 stack, i = self.idb.get_stack(self.frame, None)
  244.                 sv.load_stack(stack, i)
  245.         else:
  246.             sv = self.stackviewer
  247.             if sv and not self.vstack.get():
  248.                 self.stackviewer = None
  249.                 sv.close()
  250.             self.fstack['height'] = 1
  251.  
  252.     def show_source(self):
  253.         if self.vsource.get():
  254.             self.sync_source_line()
  255.  
  256.     def show_frame(self, (frame, lineno)):
  257.         self.frame = frame
  258.         self.show_variables()
  259.  
  260.     localsviewer = None
  261.     globalsviewer = None
  262.  
  263.     def show_locals(self):
  264.         lv = self.localsviewer
  265.         if self.vlocals.get():
  266.             if not lv:
  267.                 self.localsviewer = NamespaceViewer(self.flocals, "Locals")
  268.         else:
  269.             if lv:
  270.                 self.localsviewer = None
  271.                 lv.close()
  272.                 self.flocals['height'] = 1
  273.         self.show_variables()
  274.  
  275.     def show_globals(self):
  276.         gv = self.globalsviewer
  277.         if self.vglobals.get():
  278.             if not gv:
  279.                 self.globalsviewer = NamespaceViewer(self.fglobals, "Globals")
  280.         else:
  281.             if gv:
  282.                 self.globalsviewer = None
  283.                 gv.close()
  284.                 self.fglobals['height'] = 1
  285.         self.show_variables()
  286.  
  287.     def show_variables(self, force=0):
  288.         lv = self.localsviewer
  289.         gv = self.globalsviewer
  290.         frame = self.frame
  291.         if not frame:
  292.             ldict = gdict = None
  293.         else:
  294.             ldict = frame.f_locals
  295.             gdict = frame.f_globals
  296.             if lv and gv and ldict is gdict:
  297.                 ldict = None
  298.         if lv:
  299.             lv.load_dict(ldict, force, self.pyshell.interp.rpcclt)
  300.         if gv:
  301.             gv.load_dict(gdict, force, self.pyshell.interp.rpcclt)
  302.  
  303.     def set_breakpoint_here(self, filename, lineno):
  304.         self.idb.set_break(filename, lineno)
  305.  
  306.     def clear_breakpoint_here(self, filename, lineno):
  307.         self.idb.clear_break(filename, lineno)
  308.  
  309.     def clear_file_breaks(self, filename):
  310.         self.idb.clear_all_file_breaks(filename)
  311.  
  312.     def load_breakpoints(self):
  313.         "Load PyShellEditorWindow breakpoints into subprocess debugger"
  314.         pyshell_edit_windows = self.pyshell.flist.inversedict.keys()
  315.         for editwin in pyshell_edit_windows:
  316.             filename = editwin.io.filename
  317.             try:
  318.                 for lineno in editwin.breakpoints:
  319.                     self.set_breakpoint_here(filename, lineno)
  320.             except AttributeError:
  321.                 continue
  322.  
  323. class StackViewer(ScrolledList):
  324.  
  325.     def __init__(self, master, flist, gui):
  326.         if macosxSupport.runningAsOSXApp():
  327.             # At least on with the stock AquaTk version on OSX 10.4 you'll
  328.             # get an shaking GUI that eventually kills IDLE if the width
  329.             # argument is specified.
  330.             ScrolledList.__init__(self, master)
  331.         else:
  332.             ScrolledList.__init__(self, master, width=80)
  333.         self.flist = flist
  334.         self.gui = gui
  335.         self.stack = []
  336.  
  337.     def load_stack(self, stack, index=None):
  338.         self.stack = stack
  339.         self.clear()
  340.         for i in range(len(stack)):
  341.             frame, lineno = stack[i]
  342.             try:
  343.                 modname = frame.f_globals["__name__"]
  344.             except:
  345.                 modname = "?"
  346.             code = frame.f_code
  347.             filename = code.co_filename
  348.             funcname = code.co_name
  349.             import linecache
  350.             sourceline = linecache.getline(filename, lineno)
  351.             import string
  352.             sourceline = string.strip(sourceline)
  353.             if funcname in ("?", "", None):
  354.                 item = "%s, line %d: %s" % (modname, lineno, sourceline)
  355.             else:
  356.                 item = "%s.%s(), line %d: %s" % (modname, funcname,
  357.                                                  lineno, sourceline)
  358.             if i == index:
  359.                 item = "> " + item
  360.             self.append(item)
  361.         if index is not None:
  362.             self.select(index)
  363.  
  364.     def popup_event(self, event):
  365.         "override base method"
  366.         if self.stack:
  367.             return ScrolledList.popup_event(self, event)
  368.  
  369.     def fill_menu(self):
  370.         "override base method"
  371.         menu = self.menu
  372.         menu.add_command(label="Go to source line",
  373.                          command=self.goto_source_line)
  374.         menu.add_command(label="Show stack frame",
  375.                          command=self.show_stack_frame)
  376.  
  377.     def on_select(self, index):
  378.         "override base method"
  379.         if 0 <= index < len(self.stack):
  380.             self.gui.show_frame(self.stack[index])
  381.  
  382.     def on_double(self, index):
  383.         "override base method"
  384.         self.show_source(index)
  385.  
  386.     def goto_source_line(self):
  387.         index = self.listbox.index("active")
  388.         self.show_source(index)
  389.  
  390.     def show_stack_frame(self):
  391.         index = self.listbox.index("active")
  392.         if 0 <= index < len(self.stack):
  393.             self.gui.show_frame(self.stack[index])
  394.  
  395.     def show_source(self, index):
  396.         if not (0 <= index < len(self.stack)):
  397.             return
  398.         frame, lineno = self.stack[index]
  399.         code = frame.f_code
  400.         filename = code.co_filename
  401.         if os.path.isfile(filename):
  402.             edit = self.flist.open(filename)
  403.             if edit:
  404.                 edit.gotoline(lineno)
  405.  
  406.  
  407. class NamespaceViewer:
  408.  
  409.     def __init__(self, master, title, dict=None):
  410.         width = 0
  411.         height = 40
  412.         if dict:
  413.             height = 20*len(dict) # XXX 20 == observed height of Entry widget
  414.         self.master = master
  415.         self.title = title
  416.         import repr
  417.         self.repr = repr.Repr()
  418.         self.repr.maxstring = 60
  419.         self.repr.maxother = 60
  420.         self.frame = frame = Frame(master)
  421.         self.frame.pack(expand=1, fill="both")
  422.         self.label = Label(frame, text=title, borderwidth=2, relief="groove")
  423.         self.label.pack(fill="x")
  424.         self.vbar = vbar = Scrollbar(frame, name="vbar")
  425.         vbar.pack(side="right", fill="y")
  426.         self.canvas = canvas = Canvas(frame,
  427.                                       height=min(300, max(40, height)),
  428.                                       scrollregion=(0, 0, width, height))
  429.         canvas.pack(side="left", fill="both", expand=1)
  430.         vbar["command"] = canvas.yview
  431.         canvas["yscrollcommand"] = vbar.set
  432.         self.subframe = subframe = Frame(canvas)
  433.         self.sfid = canvas.create_window(0, 0, window=subframe, anchor="nw")
  434.         self.load_dict(dict)
  435.  
  436.     dict = -1
  437.  
  438.     def load_dict(self, dict, force=0, rpc_client=None):
  439.         if dict is self.dict and not force:
  440.             return
  441.         subframe = self.subframe
  442.         frame = self.frame
  443.         for c in subframe.children.values():
  444.             c.destroy()
  445.         self.dict = None
  446.         if not dict:
  447.             l = Label(subframe, text="None")
  448.             l.grid(row=0, column=0)
  449.         else:
  450.             names = dict.keys()
  451.             names.sort()
  452.             row = 0
  453.             for name in names:
  454.                 value = dict[name]
  455.                 svalue = self.repr.repr(value) # repr(value)
  456.                 # Strip extra quotes caused by calling repr on the (already)
  457.                 # repr'd value sent across the RPC interface:
  458.                 if rpc_client:
  459.                     svalue = svalue[1:-1]
  460.                 l = Label(subframe, text=name)
  461.                 l.grid(row=row, column=0, sticky="nw")
  462.                 l = Entry(subframe, width=0, borderwidth=0)
  463.                 l.insert(0, svalue)
  464.                 l.grid(row=row, column=1, sticky="nw")
  465.                 row = row+1
  466.         self.dict = dict
  467.         # XXX Could we use a <Configure> callback for the following?
  468.         subframe.update_idletasks() # Alas!
  469.         width = subframe.winfo_reqwidth()
  470.         height = subframe.winfo_reqheight()
  471.         canvas = self.canvas
  472.         self.canvas["scrollregion"] = (0, 0, width, height)
  473.         if height > 300:
  474.             canvas["height"] = 300
  475.             frame.pack(expand=1)
  476.         else:
  477.             canvas["height"] = height
  478.             frame.pack(expand=0)
  479.  
  480.     def close(self):
  481.         self.frame.destroy()
  482.